package medium;

import java.util.HashMap;

/**
 * 6. Z 字形变换
 * 将一个给定字符串 s 根据给定的行数 numRows ，以从上往下、从左到右进行 Z 字形排列。
 * 比如输入字符串为 "PAYPALISHIRING" 行数为 3 时，排列如下：
 * P   A   H   N
 * A P L S I I G
 * Y   I   R
 * 之后，你的输出需要从左往右逐行读取，产生出一个新的字符串，比如："PAHNAPLSIIGYIR"。
 * 请你实现这个将字符串进行指定行数变换的函数：

 * 示例 1：
 *
 * 输入：s = "PAYPALISHIRING", numRows = 3
 * 输出："PAHNAPLSIIGYIR"
 * 示例 2：
 * 输入：s = "PAYPALISHIRING", numRows = 4
 * 输出："PINALSIGYAHRPI"
 * 解释：
 * P     I    N
 * A   L S  I G
 * Y A   H R
 * P     I
 */
public class T7 {
    public static void main(String[] args) {
        System.out.println(convert("PAYPALISHIRING", 3));
    }

    public static String convert(String s, int numRows) {
        // 判断输入字符串长度或行数是否为1，如果是，则直接返回原字符串，无需处理
        if (s.length()==1||numRows==1){
            return s;
        }

        // 初始化标志变量flag，用于跟踪当前字符应放入的行数
        int flag = 1;

        // 使用HashMap存储每一行的字符序列，键为行号，值为该行的字符缓冲区
        HashMap<Integer, StringBuffer> map = new HashMap<>();

        // 将字符串的第一个字符放入第一行，作为起始
        map.put(1, new StringBuffer().append(s.charAt(0)));

        // 对flag进行递增，以跟踪下一个字符应放入的行号
        flag++;

        // 遍历字符串的每个字符，从第二个字符开始
        for (int i = 1; i < s.length(); i++) {
            // 如果当前行已存在，则将当前字符追加到该行的字符缓冲区中
            if (map.containsKey(Math.abs(flag))) {
                map.put(Math.abs(flag), map.get(Math.abs(flag)).append(s.charAt(i)));
                flag++;
            } else {
                // 如果当前行不存在，则创建一个新的字符缓冲区，并将当前字符放入
                map.put(Math.abs(flag), new StringBuffer().append(s.charAt(i)));
                flag++;
            }

            // 当flag超过行数限制或变为负数时，调整flag的值，以实现Z字形的行号变化
            if (flag > numRows || Math.abs(flag) == 0) {
                flag = flag == 0 ? 2 : -flag + 2;
            }
        }

        // 创建一个新的字符缓冲区，用于拼接所有行的字符序列
        StringBuffer sb = new StringBuffer();

        // 遍历HashMap中的每个键值对，将每一行的字符序列按顺序拼接到sb中
        for (int i = 1; i <= map.size(); i++) {
            sb.append(map.get(i));
        }

        // 将拼接好的字符缓冲区转换为字符串，并返回
        return String.valueOf(sb);
    }
}
